home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Presentations / Presentations ’93 / Macintosh as Internet Server ƒ / inetd / InetD.cp next >
Encoding:
Text File  |  1993-04-27  |  11.3 KB  |  496 lines  |  [TEXT/MPS ]

  1. //---------------------------------------------------------------------
  2. //
  3. //    Copyright © 1992 David Peterson.
  4. //    All rights reserved.
  5. //
  6. //    Permission to use, copy, modify, and distribute this software for
  7. //    any purpose and without fee is hereby granted, provided that the
  8. //    above copyright notice appear in all copies and that both that
  9. //    copyright notice and this permission notice appear in supporting
  10. //    documentation.
  11. //
  12. //---------------------------------------------------------------------
  13.  
  14. #include "InetD.h"
  15. #include "TCP.h"
  16. #include "UDP.h"
  17.  
  18. #include <UFailure.h>
  19. #include <myUtils.h>
  20.  
  21. #include <Folders.h>
  22. #include <Devices.h>
  23. #include <Resources.h>
  24. #include <Errors.h>
  25. #include <Packages.h>
  26. #include <Sysequ.h>
  27. #include <GestaltEqu.h>
  28. #include <ToolUtils.h>
  29.  
  30. #include <String.h>
  31. #include <StdArg.h>
  32. #include <StdIO.h>
  33.  
  34. void main();
  35.  
  36. /*    Any failure in the program will bring execution back here, if that happens,
  37.     I need to set up another failure handler and try to clean up nicely (which
  38.     attempts to gracefully release all connections) which can fail as well. If
  39.     that happens, just punt.
  40. */
  41. void
  42. main()
  43. {
  44.     InetD*        aDaemon = nil;
  45.     FailInfo    fi;
  46.  
  47.     VOLATILE(aDaemon);
  48.     
  49.     InitUDaemonApp(*((long*) DefltStack));
  50.     
  51.     if (CheckSystem()) {
  52.         if (fi.Try()) {
  53.             aDaemon = new InetD;
  54.             FailNIL(aDaemon);
  55.         
  56.             aDaemon->Initialize();
  57.             aDaemon->Run();
  58.             
  59.             delete aDaemon;
  60.             
  61.             fi.Success();
  62.         }
  63.         else if (aDaemon) {
  64.             FailInfo    tmp;
  65.             
  66.             if (tmp.Try()) {
  67.                 aDaemon->LogIt(true, "InetD:\n\nFailed with OSErr = %d, cleaning up\n", fi.error);
  68.                 tmp.Success();
  69.             }
  70.             if (tmp.Try()) {
  71.                 delete aDaemon;
  72.                 tmp.Success();
  73.             }
  74.         }
  75.     }
  76. }
  77.  
  78. /*    Check for: AppleEvents, FindFolder, Notification Mgr, Process Mgr, MacTCP.
  79.     Just for grins, I check for A/UX and punt if its around -- you'd have to
  80.     be nuts to try and use a hack like this if you're running UNIX.
  81.     
  82.     The macro is pretty hideous, but simplifies things a bit - I stole it from
  83.     MacApp 3.0.1.
  84. */
  85. Boolean
  86. CheckSystem()
  87. {
  88.     long    response;
  89.     Boolean    cont;
  90.     
  91.     #define mHasIt(attr, bit) ((Gestalt(attr, &response) == noErr) && (((response >> bit) & 1) != 0))
  92.  
  93.     cont = (Gestalt(gestaltAUXVersion, &response) != noErr);
  94.  
  95.     cont = (cont && (Gestalt('mtcp', &response) == noErr));
  96.     
  97.     cont = (cont && mHasIt(gestaltAppleEventsAttr, gestaltAppleEventsPresent));
  98.     cont = (cont && mHasIt(gestaltFindFolderAttr, gestaltFindFolderPresent));
  99.     cont = (cont && mHasIt(gestaltNotificationMgrAttr, gestaltNotificationPresent));
  100.     cont = (cont && mHasIt(gestaltOSAttr, gestaltLaunchControl));
  101.     cont = (cont && mHasIt(gestaltOSAttr, gestaltLaunchFullFileSpec));
  102.  
  103.     return cont;
  104. }
  105.  
  106. InetD::InetD()
  107. {
  108.     fLogFile            = 0;
  109.     fTCP                = nil;
  110.     fUDP                = nil;
  111.     
  112.     FailOSErr(OpenDriver("\p.ipp", &fDriverRef));
  113. }
  114.  
  115. InetD::~InetD()
  116. {
  117.     if (fTCP) delete fTCP;
  118.     if (fUDP) delete fUDP;
  119.     
  120.     this->LogIt(false, "Shutting down\n");
  121.         
  122.     if (fLogFile) FSClose(fLogFile);
  123. }
  124.  
  125. void
  126. InetD::Initialize()
  127. {
  128.     Inherited::Initialize();
  129.  
  130.     short    resFile;
  131.     short    curResFile;
  132.     
  133.     short    vRefNum;
  134.     long    dirID;
  135.     
  136.     FSSpec    logfile;
  137.     Str255    prepname;
  138.     Str255    logname;
  139.         
  140.     GetIndString(prepname, kFileNames, kPrepFile);
  141.     GetIndString(logname, kFileNames, kLogFile);
  142.  
  143.     FindFolder(kOnSystemDisk, kPreferencesFolderType, false, &vRefNum, &dirID);
  144.  
  145.     if (FSMakeFSSpec(vRefNum, dirID, logname, &logfile) == fnfErr) 
  146.         FSpCreate(&logfile, 'MPS ', 'TEXT', smSystemScript);
  147.         
  148.     FailOSErr(FSpOpenDF(&logfile, fsRdWrPerm, &fLogFile));
  149.     FailOSErr(SetFPos(fLogFile, fsFromLEOF, 0));
  150.  
  151.     this->LogIt(false, "Starting up\n");
  152.  
  153.     if (FSMakeFSSpec(vRefNum, dirID, prepname, &fPrepFile) == fnfErr)
  154.         FSpCreateResFile(&fPrepFile, 'inet', 'prep', smSystemScript);
  155.  
  156.     resFile = FSpOpenResFile(&fPrepFile, fsRdPerm);
  157.     FailResError();
  158.     curResFile = SwitchResFile(resFile);
  159.     
  160.     this->NewTCPListener();
  161.     this->NewUDPListener();
  162.     
  163.     SwitchResFile(curResFile);
  164.     CloseResFile(resFile);
  165. }
  166.  
  167. /*    Encapsulate the process some so that it can be easily done from
  168.     AEResetHandler. The Initialize will return false if there were
  169.     no 'TCP ' resources found, this isn't neccessarily an error
  170.     because its possible that none were created with the control panel.
  171. */
  172. void
  173. InetD::NewTCPListener()
  174. {
  175.     TCPListener*    nu;
  176.     
  177.     if (fTCP) {
  178.         delete fTCP;
  179.         fTCP = nil;
  180.     }
  181.     
  182.     nu = new TCPListener(this);
  183.     FailNIL(nu);
  184.     
  185.     if (nu->Initialize())
  186.         fTCP = nu;
  187.     else
  188.         delete nu;
  189. }
  190.  
  191. void
  192. InetD::NewUDPListener()
  193. {
  194.     UDPListener*    nu;
  195.     
  196.     if (fUDP) {
  197.         delete fUDP;
  198.         fUDP = nil;
  199.     }
  200.     
  201.     nu = new UDPListener(this);
  202.     FailNIL(nu);
  203.     
  204.     if (nu->Initialize())
  205.         fUDP = nu;
  206.     else
  207.         delete nu;
  208. }
  209.  
  210. void 
  211. InetD::InstallAEHandlers()
  212. {
  213.     Inherited::InstallAEHandlers();
  214.  
  215.     FailOSErr(AEInstallEventHandler(kCoreEventClass, kAEApplicationDied,
  216.                 (EventHandlerProcPtr) &AEDeathHandler, (long) this, false));
  217.                                     
  218.     FailOSErr(AEInstallEventHandler('INET', 'TNFY',
  219.                 (EventHandlerProcPtr) &AETCPNotificationHandler, (long) this, false));
  220.  
  221.     FailOSErr(AEInstallEventHandler('INET', 'UNFY',
  222.                 (EventHandlerProcPtr) &AEUDPNotificationHandler, (long) this, false));
  223.  
  224.     FailOSErr(AEInstallEventHandler('INET', 'RSET',
  225.                 (EventHandlerProcPtr) &AEResetHandler, (long) this, false));
  226. }
  227.  
  228. void
  229. InetD::Launch(StreamPtr stream, FSSpec* process, AEEventID type, PSN* psn)
  230. {
  231.     OSErr                result;
  232.     AppleEvent            theEvent;
  233.     AEAddressDesc        myAddress;
  234.     AEDesc                launchDesc;
  235.     LaunchParamBlockRec    lpb;
  236.     Boolean                theyare;
  237.     
  238.     theyare = this->IsRunning(process->name, psn);
  239.     
  240.     FailOSErr(AECreateDesc(typeProcessSerialNumber, (Ptr) psn, sizeof(PSN), &myAddress));
  241.     FailOSErr(AECreateAppleEvent('INET', type, &myAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent));
  242.     FailOSErr(AEPutParamPtr(&theEvent, 'STRM', typeLongInteger, (Ptr) &stream, sizeof(StreamPtr)));
  243.  
  244.     if (theyare) {
  245.         result = AESend(&theEvent, nil, kAENoReply, kAEHighPriority, 0, nil, nil);
  246.     }
  247.     else {
  248.         FailOSErr(AECoerceDesc(&theEvent, typeAppParameters, &launchDesc));
  249.     
  250.         HLock(launchDesc.dataHandle);
  251.     
  252.         lpb.launchAppParameters = (AppParameters*) *(launchDesc.dataHandle);
  253.         lpb.launchBlockID = extendedBlock;
  254.         lpb.launchEPBLength = extendedBlockLen;
  255.         lpb.launchFileFlags = 0;
  256.         lpb.launchControlFlags = launchContinue + launchNoFileFlags;
  257.         lpb.launchAppSpec = process;
  258.         
  259.         result = LaunchApplication(&lpb);
  260.         
  261.         HUnlock(launchDesc.dataHandle);
  262.         
  263.         psn->highLongOfPSN = lpb.launchProcessSN.highLongOfPSN;
  264.         psn->lowLongOfPSN = lpb.launchProcessSN.lowLongOfPSN;
  265.         
  266.         AEDisposeDesc(&launchDesc);
  267.     }
  268.  
  269.     AEDisposeDesc(&theEvent);
  270.     AEDisposeDesc(&myAddress);
  271.     
  272.     FailOSErr(result);
  273. }
  274.  
  275. Boolean
  276. InetD::IsRunning(Str63 name, PSN* ts)
  277. {
  278.     ProcessSerialNumber    psn;
  279.     ProcessInfoRec        prc;
  280.     Boolean                found = false;
  281.     Str63                pname;
  282.     
  283.     psn.highLongOfPSN = 0;
  284.     psn.lowLongOfPSN = kNoProcess;
  285.     
  286.     prc.processInfoLength = sizeof(ProcessInfoRec);
  287.     prc.processName = pname;
  288.     prc.processAppSpec = nil;
  289.  
  290.     while (!found && (GetNextProcess(&psn) == noErr)) {
  291.         if (GetProcessInformation(&psn, &prc) == noErr) {
  292.             if (IUCompString(pname, name) == 0) {
  293.                 ts->highLongOfPSN = psn.highLongOfPSN;
  294.                 ts->lowLongOfPSN = psn.lowLongOfPSN;            
  295.                 found = true;
  296.             }
  297.         }
  298.     }
  299.     
  300.     return found;
  301. }
  302.  
  303. void
  304. InetD::DoNull()
  305. {
  306.     short        resFile;
  307.     short        curResFile;
  308.         
  309.     resFile = FSpOpenResFile(&fPrepFile, fsRdPerm);
  310.     FailResError();
  311.     curResFile = SwitchResFile(resFile);
  312.         
  313.     if (fTCP) fTCP->DoNull();
  314.     if (fUDP) fUDP->DoNull();
  315.     
  316.     SwitchResFile(curResFile);
  317.     CloseResFile(resFile);
  318. }
  319.  
  320. void
  321. InetD::LogIt(Boolean postit, char* form, ...)
  322. {
  323.     va_list         ap;
  324.     long            len;
  325.     unsigned long    time;
  326.     Str63            datestr;
  327.     Str63            timestr;
  328.     char            datetime[255];
  329.     char            str[255];
  330.     
  331.     FailInfo         fi;
  332.     
  333.     str[0] = 0;
  334.     datetime[0] = 0;
  335.     
  336.     va_start(ap, form);
  337.     vsprintf(str, form, ap);
  338.     va_end(ap);
  339.     
  340.     if (postit && fi.Try()) {
  341.         this->PostNotification(str);
  342.         fi.Success();
  343.     }
  344.     
  345.     GetDateTime(&time);
  346.     IUDateString(time, shortDate, datestr);
  347.     IUTimeString(time, true, timestr);
  348.     
  349.     sprintf(datetime, "%P\t%P:\t\t", datestr, timestr);
  350.     
  351.     if (fi.Try()) {
  352.         len = strlen(datetime);
  353.         if (fLogFile) FailOSErr(FSWrite(fLogFile, &len, datetime));
  354.         
  355.         len = strlen(str);
  356.         if (fLogFile) FailOSErr(FSWrite(fLogFile, &len, str)); 
  357.         fi.Success();
  358.     }
  359. }
  360.  
  361. pascal OSErr 
  362. AEDeathHandler(AppleEvent* messagein, AppleEvent* /*reply*/, long refIn)
  363. {
  364.     AEDesc    psnDesc;
  365.     OSErr    theErr    = noErr;
  366.     InetD*    inet    = (InetD*) refIn;
  367.     PSN        psn;
  368.     
  369.     if ((theErr = AEGetParamDesc(messagein, keyProcessSerialNumber, typeProcessSerialNumber, &psnDesc)) == noErr) {
  370.         psn.highLongOfPSN = ((PSN*) *psnDesc.dataHandle)->highLongOfPSN;
  371.         psn.lowLongOfPSN = ((PSN*) *psnDesc.dataHandle)->lowLongOfPSN;
  372.         
  373.         AEDisposeDesc(&psnDesc);
  374.     }
  375.  
  376.     short    save    = TurnOffInterrupts();
  377.  
  378.     inet->fTCP->UnNotify(&psn);
  379.     inet->fUDP->UnNotify(&psn);
  380.  
  381.     TurnOnInterrupts(save);
  382.     
  383.     inet->fUDP->ListenAgain(&psn);
  384.  
  385.     return theErr;
  386. }
  387.  
  388. pascal OSErr
  389. AETCPNotificationHandler(AppleEvent* messagein, AppleEvent* /*reply*/, long refIn)
  390. {
  391.     ProcPtr        proc    = nil;
  392.     StreamPtr    stream    = nil;
  393.     Ptr            usrPtr    = nil;
  394.     PSN            psn;
  395.     InetD*         inet     = (InetD*) refIn;
  396.     
  397.     AEDesc        streamDesc, notifyDesc, psnDesc, ptrDesc;
  398.     
  399.     FailInfo    fi;
  400.     
  401.     if (fi.Try()) {
  402.         FailOSErr(AEGetParamDesc(messagein, 'STRM', typeLongInteger, &streamDesc));
  403.         FailOSErr(AEGetParamDesc(messagein, 'ASR ', typeLongInteger, ¬ifyDesc));
  404.         FailOSErr(AEGetParamDesc(messagein, 'USRP', typeLongInteger, &ptrDesc));
  405.         FailOSErr(AEGetParamDesc(messagein, keyProcessSerialNumber, typeProcessSerialNumber, &psnDesc));
  406.         
  407.         stream = *((StreamPtr*) *streamDesc.dataHandle);
  408.         proc = *((ProcPtr*) *notifyDesc.dataHandle);
  409.         usrPtr = *((Ptr*) *ptrDesc.dataHandle);
  410.         psn.highLongOfPSN = ((PSN*) *psnDesc.dataHandle)->highLongOfPSN;
  411.         psn.lowLongOfPSN = ((PSN*) *psnDesc.dataHandle)->lowLongOfPSN;
  412.     
  413.         AEDisposeDesc(&streamDesc);
  414.         AEDisposeDesc(¬ifyDesc);
  415.         AEDisposeDesc(&psnDesc);
  416.         AEDisposeDesc(&psnDesc);
  417.     
  418.         fi.Success();
  419.     }
  420.     else {
  421.         inet->LogIt(false, "Malformed TCP notification AE\n");
  422.     }
  423.  
  424.     short save    = TurnOffInterrupts();
  425.     inet->fTCP->NotifyMe(&psn, stream, proc, usrPtr);
  426.     TurnOnInterrupts(save);
  427.  
  428.     return fi.error;
  429. }
  430.  
  431. pascal OSErr
  432. AEUDPNotificationHandler(AppleEvent* messagein, AppleEvent* /*reply*/, long refIn)
  433. {
  434.     ProcPtr        proc    = nil;
  435.     StreamPtr    stream    = nil;
  436.     Ptr            usrPtr    = nil;
  437.     PSN            psn;
  438.     InetD*         inet     = (InetD*) refIn;
  439.     
  440.     AEDesc        streamDesc, notifyDesc, psnDesc, ptrDesc;
  441.     
  442.     FailInfo    fi;
  443.     
  444.     if (fi.Try()) {
  445.         FailOSErr(AEGetParamDesc(messagein, 'STRM', typeLongInteger, &streamDesc));
  446.         FailOSErr(AEGetParamDesc(messagein, 'ASR ', typeLongInteger, ¬ifyDesc));
  447.         FailOSErr(AEGetParamDesc(messagein, 'USRP', typeLongInteger, &ptrDesc));
  448.         FailOSErr(AEGetParamDesc(messagein, keyProcessSerialNumber, typeProcessSerialNumber, &psnDesc));
  449.         
  450.         stream = *((StreamPtr*) *streamDesc.dataHandle);
  451.         proc = *((ProcPtr*) *notifyDesc.dataHandle);
  452.         usrPtr = *((Ptr*) *ptrDesc.dataHandle);
  453.         psn.highLongOfPSN = ((PSN*) *psnDesc.dataHandle)->highLongOfPSN;
  454.         psn.lowLongOfPSN = ((PSN*) *psnDesc.dataHandle)->lowLongOfPSN;
  455.     
  456.         AEDisposeDesc(&streamDesc);
  457.         AEDisposeDesc(¬ifyDesc);
  458.         AEDisposeDesc(&psnDesc);
  459.         AEDisposeDesc(&psnDesc);
  460.     
  461.         fi.Success();
  462.     }
  463.     else {
  464.         inet->LogIt(false, "Malformed UDP notification AE\n");
  465.     }
  466.  
  467.     short save    = TurnOffInterrupts();
  468.     inet->fUDP->NotifyMe(&psn, stream, proc, usrPtr);
  469.     TurnOnInterrupts(save);
  470.  
  471.     return fi.error;
  472. }
  473.  
  474. pascal OSErr
  475. AEResetHandler(AppleEvent* /*messagein*/, AppleEvent* /*reply*/, long refIn)
  476. {
  477.     short    resFile;
  478.     short    curResFile;
  479.     InetD*     inet = (InetD*) refIn;
  480.         
  481.     inet->LogIt(false, "Caught reset signal\n");
  482.  
  483.     resFile = FSpOpenResFile(&inet->fPrepFile, fsRdPerm);
  484.     FailResError();
  485.     curResFile = SwitchResFile(resFile);
  486.  
  487.     inet->NewTCPListener();
  488.     inet->NewUDPListener();
  489.     
  490.     SwitchResFile(curResFile);
  491.     CloseResFile(resFile);
  492.  
  493.     return noErr;
  494. }
  495.  
  496.